/*
 * This file is Copyright 2002-2006 Loyola University Chicago,
 * Department of Computer Science and the Emerging Technologies Laboratory.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License via
 *    http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.citep.web.admin.transactions.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

import com.citep.web.admin.accounts.client.AccountEntryModule;
import com.citep.web.admin.accounts.client.AccountService;
import com.citep.web.admin.accounts.client.AccountServiceAsync;
import com.citep.web.gwt.cache.*;
import com.citep.web.gwt.dto.*;
import com.citep.web.gwt.module.*;
import com.citep.web.gwt.widgets.*;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.History;


public class TransactionEntryApplication extends BaseApplication implements DynaTableDataProvider  {

	protected AccountTreeCache cache = AccountTreeCache.getCache();
	
	protected String formatDate(Date d) {
		return "" + (d.getMonth()+1) + "/" + d.getDate() + "/" + (d.getYear() + 1900);
	}
	
	protected void pushResults(ArrayList entryList, int startRow, RowDataAcceptor acceptor) {
		int listSize = entryList.size();
		
		String [][] rows = new String[listSize][];
		
		for(int i = 0; i < listSize; i++) {
			EntryInfo entryInfo = (EntryInfo)entryList.get(i);
			rows[i] = new String[6];
			rows[i][0] = formatDate(entryInfo.getDate());
			rows[i][1] = entryInfo.getEntry().getMemo();
			
			int sourceAccountId = entryInfo.getEntry().getSourceAccountId();
			if(sourceAccountId != 0) {
				AccountDTO source = cache.getAccount(sourceAccountId);
				rows[i][2] = (source != null)?source.getName():"null";
			} else {
				rows[i][2] = "-split-";
			}
			
			//rows[i][2] = currentAccount.getName();
			
			if(entryInfo.getEntry().getType().equals("DEBIT")) {
				rows[i][3] = entryInfo.getEntry().getAmount();
			} else if(entryInfo.getEntry().getType().equals("CREDIT")) {
				rows[i][4] = entryInfo.getEntry().getAmount();
			}

			rows[i][5] = entryInfo.getBalance();
		}
		
		acceptor.accept(startRow, rows);
	}
	
	public void updateRowData(final int startRow, final int maxRows, final RowDataAcceptor acceptor) {
		// TODO Auto-generated method stub
		getTransactionsCallBack = new AsyncCallback() {
			public void onSuccess(Object result) {
				ArrayList entryList = (ArrayList)result;
				pushResults(entryList,startRow,acceptor);
			}
			
			public void onFailure(Throwable caught) {
				System.out.println(":" + caught.getMessage());
				caught.printStackTrace();
			}
		};

		if(currentAccount != null)
			accountsService.getAccountEntries(currentAccount, startRow, maxRows, getTransactionsCallBack);
	}

	protected TransactionEntryPresentation presentation;

	protected AccountServiceAsync accountsService;

	protected AsyncCallback entryTypesCallBack;
	protected AsyncCallback openAccountCallBack;
	protected AsyncCallback addTransactionCallBack;
	protected AsyncCallback getTransactionsCallBack;
	
	protected AccountDTO currentAccount; //the currently open account

	protected HashMap accountMap = new HashMap(); //maps account names to accountDTO objects
	
	public TransactionEntryApplication() {
		accountsService = (AccountServiceAsync)GWT.create(AccountService.class);
		((ServiceDefTarget)accountsService).setServiceEntryPoint(GWT.getModuleBaseURL() + "/accounts");
	}
	
	public void setPresentation(TransactionEntryPresentation presentation) {
		this.presentation = presentation;
	}
	
	private void recurseTree(AccountTreeNode node, int level, int count) {
		AccountDTO account = node.getAccount();
		
		if(account != null) {
			presentation.addAccountToSelect(account.getName());
			accountMap.put(account.getName(), account);
			//add only the first 10 accounts to the shortcut table
			if(count < 10)
				presentation.addShortcut(new AccountTransactionsShortcut(account.getName(),account.getId()), false);
		}
		
		if(node.getChildren() != null) {
			for(int i = 0; i < node.getChildren().size(); i++) {
				AccountTreeNode child = (AccountTreeNode)node.getChildren().get(i);
				recurseTree(child,level+1,++count);
			}
		}
	}
	
	public void refreshAccountList() {
		accountMap.clear();
		presentation.clearShortcuts();
		presentation.clearAccountSelection();
		cache.getAccountTree(new AccountTreeListenerAdapter() {
			public void onAccountTreeReady(AccountTreeNode root) {
				if(root != null && root.getChildren() != null) {
					for(int i = 0; i < root.getChildren().size(); i++)
						recurseTree((AccountTreeNode)root.getChildren().get(i),0,i);
				}
			}
			
			public void onAccountTreeLoadFailure(Throwable t) {
				presentation.displayError("", t.getMessage());
			}	
		});
	}

	
	
	public void refreshEntryTypes() {
		presentation.clearEntryTypes();
		accountsService.getEntryTypes(getEntryTypesCallBack());
	}
	
	protected AsyncCallback getEntryTypesCallBack() {
		if(entryTypesCallBack == null) {
			entryTypesCallBack = new AsyncCallback() {
				public void onSuccess(Object result) {
					ArrayList entryTypes = (ArrayList) result;
					for(int i = 0; i < entryTypes.size(); i++) {
						presentation.addEntryType((String)entryTypes.get(i));
					}
				}
				
				public void onFailure(Throwable caught) {
					processException(presentation,caught);
				}
			};
		}
		return entryTypesCallBack;
	}
	
	public void openAccount(int accountId) {
		presentation.setLoadingState();
		accountsService.getAccount(accountId, getOpenAccountCallBack());
	}
	
	protected AsyncCallback getOpenAccountCallBack() {
		if(openAccountCallBack == null) {
			openAccountCallBack = new AsyncCallback() {
				public void onSuccess(Object result) {
					
					presentation.setReadyState();
					
					AccountDTO account = (AccountDTO)result;
					if(account != null) {
						currentAccount = account;
						presentation.setTitle("Transactions for: " + account.getName());
						presentation.refreshTransactions();
					}
				}
				
				public void onFailure(Throwable caught) {
					presentation.setReadyState();
					processException(presentation,caught);
				}
			};
		}
		
		return openAccountCallBack;
	}
	
	public void addTransaction(String accountName,String entryType, String memo, Date transactionDate, String amount) {
		
		AccountDTO account = (AccountDTO)accountMap.get(accountName);
		
		if(currentAccount != null)
			accountsService.createTransaction(currentAccount, account, entryType, memo, transactionDate, amount, getAddTransactionCallBack());
		else
			presentation.displayError("addTransaction", "Please select an account from the shortcut menu");
	}
	
	protected AsyncCallback getAddTransactionCallBack() {
		if(addTransactionCallBack == null) {
			addTransactionCallBack = new AsyncCallback() {
				public void onSuccess(Object result) {
					presentation.setReadyState();
					presentation.displayStatus("Transaction added", 1);
					presentation.refreshTransactions();
				}
				
				public void onFailure(Throwable caught) {
					presentation.setReadyState();
					processException(presentation,caught);
				}
			};
		}
		
		return addTransactionCallBack;
	}
	
	public void launchEditAccount() {
		if(currentAccount != null) {
			String token = HistoryEncoder.encode("edit_account", new Integer(currentAccount.getId()));
			History.newItem(token);
		}
	}
	
}